package com.appgemacht.postinews.util;

import android.app.Activity;
import android.os.Build;
import android.view.View;

/**
 * A utility class that helps with showing and hiding system UI such as the
 * status bar and navigation/system bar. This class uses backward-compatibility
 * techniques described in <a href=
 * "http://developer.android.com/training/backward-compatible-ui/index.html">
 * Creating Backward-Compatible UIs</a> to ensure that devices running any
 * version of ndroid OS are supported. More specifically, there are separate
 * implementations of this abstract class: for newer devices,
 * {@link #getInstance} will return a {@link SystemUiHiderHoneycomb} instance,
 * while on older devices {@link #getInstance} will return a
 * {@link SystemUiHiderBase} instance.
 * <p>
 * For more on system bars, see <a href=
 * "http://developer.android.com/design/get-started/ui-overview.html#system-bars"
 * > System Bars</a>.
 * 
 * @see android.view.View#setSystemUiVisibility(int)
 * @see android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN
 */
public abstract class SystemUiHider {
  /**
   * When this flag is set, the
   * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN} flag
   * will be set on older devices, making the status bar "float" on top of the
   * activity layout. This is most useful when there are no controls at the top
   * of the activity layout.
   * <p>
   * This flag isn't used on newer devices because the <a
   * href="http://developer.android.com/design/patterns/actionbar.html">action
   * bar</a>, the most important structural element of an Android app, should be
   * visible and not obscured by the system UI.
   */
  public static final int FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES = 0x1;

  /**
   * When this flag is set, {@link #show()} and {@link #hide()} will toggle the
   * visibility of the status bar. If there is a navigation bar, show and hide
   * will toggle low profile mode.
   */
  public static final int FLAG_FULLSCREEN = 0x2;

  /**
   * When this flag is set, {@link #show()} and {@link #hide()} will toggle the
   * visibility of the navigation bar, if it's present on the device and the
   * device allows hiding it. In cases where the navigation bar is present but
   * cannot be hidden, show and hide will toggle low profile mode.
   */
  public static final int FLAG_HIDE_NAVIGATION = FLAG_FULLSCREEN | 0x4;

  /**
   * The activity associated with this UI hider object.
   */
  protected Activity mActivity;

  /**
   * The view on which {@link View#setSystemUiVisibility(int)} will be called.
   */
  protected View mAnchorView;

  /**
   * The current UI hider flags.
   * 
   * @see #FLAG_FULLSCREEN
   * @see #FLAG_HIDE_NAVIGATION
   * @see #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES
   */
  protected int mFlags;

  /**
   * The current visibility callback.
   */
  protected OnVisibilityChangeListener mOnVisibilityChangeListener = sDummyListener;

  /**
   * Creates and returns an instance of {@link SystemUiHider} that is
   * appropriate for this device. The object will be either a
   * {@link SystemUiHiderBase} or {@link SystemUiHiderHoneycomb} depending on
   * the device.
   * 
   * @param activity
   *          The activity whose window's system UI should be controlled by this
   *          class.
   * @param anchorView
   *          The view on which {@link View#setSystemUiVisibility(int)} will be
   *          called.
   * @param flags
   *          Either 0 or any combination of {@link #FLAG_FULLSCREEN},
   *          {@link #FLAG_HIDE_NAVIGATION}, and
   *          {@link #FLAG_LAYOUT_IN_SCREEN_OLDER_DEVICES}.
   */
  public static SystemUiHider getInstance(Activity activity, View anchorView,
      int flags) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
      return new SystemUiHiderHoneycomb(activity, anchorView, flags);
    } else {
      return new SystemUiHiderBase(activity, anchorView, flags);
    }
  }

  protected SystemUiHider(Activity activity, View anchorView, int flags) {
    mActivity = activity;
    mAnchorView = anchorView;
    mFlags = flags;
  }

  /**
   * Sets up the system UI hider. Should be called from
   * {@link Activity#onCreate}.
   */
  public abstract void setup();

  /**
   * Returns whether or not the system UI is visible.
   */
  public abstract boolean isVisible();

  /**
   * Hide the system UI.
   */
  public abstract void hide();

  /**
   * Show the system UI.
   */
  public abstract void show();

  /**
   * Toggle the visibility of the system UI.
   */
  public void toggle() {
    if (isVisible()) {
      hide();
    } else {
      show();
    }
  }

  /**
   * Registers a callback, to be triggered when the system UI visibility
   * changes.
   */
  public void setOnVisibilityChangeListener(OnVisibilityChangeListener listener) {
    if (listener == null) {
      listener = sDummyListener;
    }

    mOnVisibilityChangeListener = listener;
  }

  /**
   * A dummy no-op callback for use when there is no other listener set.
   */
  private static OnVisibilityChangeListener sDummyListener = new OnVisibilityChangeListener() {
    @Override
    public void onVisibilityChange(boolean visible) {
    }
  };

  /**
   * A callback interface used to listen for system UI visibility changes.
   */
  public interface OnVisibilityChangeListener {
    /**
     * Called when the system UI visibility has changed.
     * 
     * @param visible
     *          True if the system UI is visible.
     */
    public void onVisibilityChange(boolean visible);
  }
}
